package com.googlecode.openrtp.grizzly.rtp.filter;

import com.google.inject.Inject;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.glassfish.grizzly.Buffer;
import org.glassfish.grizzly.filterchain.BaseFilter;
import org.glassfish.grizzly.filterchain.FilterChainContext;
import org.glassfish.grizzly.filterchain.NextAction;
import com.googlecode.openrtp.grizzly.util.BufferUtil;
import com.googlecode.openrtp.spi.RtpPacket;
import com.googlecode.openrtp.spi.annotation.Priority;

/**
 *
 * my regards to
 *
 * http://java.net/projects/jrtp/sources/svn/content/trunk/src/gov/nist/jrtp/RtpPacket.java.
 *
 * it showed me how to extract the rtp header fields.
 *
 * @author jocke
 *
 *
 *
 */
@Priority(intValue = 100)
public class RtpFilter extends BaseFilter {

    private static final Logger LOG = Logger.getLogger(RtpFilter.class.getName());
    
    private final BufferUtil bufferUtil;

    @Inject
    public RtpFilter(BufferUtil bufferUtil) {
        this.bufferUtil = bufferUtil;
    }

    @Override
    public NextAction handleRead(FilterChainContext ctx) throws IOException {
       
        final Buffer sourceBuffer = ctx.getMessage();

        int vToSn = sourceBuffer.getInt();

        int v = (vToSn >>> 0x1E) & 0x03;

        int p = (vToSn >>> 0x1D) & 0x01;

        int x = (vToSn >>> 0x1C) & 0x01;

        int cc = (vToSn >>> 0x18) & 0x0F;

        int m = (vToSn >>> 0x17) & 0x01;

        int pt = (vToSn >>> 0x10) & 0x7F;

        int sn = (vToSn & 0xFFFF);

        ByteBuffer buffer = bufferUtil.allocate(ctx, 8);

        long ts = bufferUtil.getUnsignedIntAsLong(sourceBuffer, buffer);

        long ssrc = bufferUtil.getUnsignedIntAsLong(sourceBuffer, buffer);

        long[] csrc = getCsrc(cc, sourceBuffer, buffer);

        final byte[] payload = new byte[sourceBuffer.remaining()];
        
        sourceBuffer.get(payload);

        RtpPacket packet = RtpPacket.create(v, p, x, cc, m, pt, sn, ts, ssrc, csrc, payload);

        LOG.log(Level.INFO, "Packet arrived {0}", packet);

        ctx.setMessage(packet);

        sourceBuffer.tryDispose();

        bufferUtil.release(ctx, buffer);

        return super.handleRead(ctx);
    }

    private long[] getCsrc(int cc, final Buffer sourceBuffer, ByteBuffer buffer) {
        if (cc == 0) {
            return RtpPacket.EMPTY_LONG_ARRAY;

        } else {
            long[] csrc = new long[cc];
            for (int i = 0; i < csrc.length; i++) {
                csrc[i] = bufferUtil.getUnsignedIntAsLong(sourceBuffer, buffer);
            }
            return csrc;
        }
    }

    @Override
    public NextAction handleWrite(FilterChainContext ctx) throws IOException {

        RtpPacket packet = ctx.getMessage();
        
        LOG.log(Level.INFO, "Packet sending {0}", packet.getSize());

        Buffer buffer = bufferUtil.allocateBuffer(ctx, packet.getSize());

        int vToSn = 0;
        vToSn |= packet.getV();

        vToSn = putInInt(vToSn, packet.getP(), 1);
        vToSn = putInInt(vToSn, packet.getX(), 1);
        vToSn = putInInt(vToSn, packet.getCc(), 4);
        vToSn = putInInt(vToSn, packet.getM(), 1);
        vToSn = putInInt(vToSn, packet.getPt(), 7);
        vToSn = putInInt(vToSn, packet.getSn(), 16);

        buffer.putInt(vToSn);
        buffer.putInt((int) packet.getTs());
        buffer.putInt((int) packet.getSsrc());

        for (int i = 0; i < packet.getCsrc().length; i++) {
            buffer.putInt((int) packet.getCsrc()[i]);
        }
        
        buffer.put(packet.getPayload());
        
        buffer.flip();
        
        ctx.setMessage(buffer);
        
        return super.handleWrite(ctx);
    }
    
    private int putInInt(int toPut, int field, int positions) {
        toPut <<= positions;
        toPut |= field;
        return toPut;
    }
}
